package com.ht.config.security;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ht.abnormal.HtException;
import com.ht.constant.DicConstants;
import com.ht.constant.RedisConstants;
import com.ht.module.sys.entity.SysMenu;
import com.ht.module.sys.entity.SysRole;
import com.ht.module.sys.entity.SysUser;
import com.ht.module.sys.mapper.SysMenuMapper;
import com.ht.module.sys.service.ISysMenuService;
import com.ht.module.sys.service.ISysUserRoleService;
import com.ht.module.sys.service.ISysUserService;
import com.ht.util.RedisUtil;
import com.ht.util.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ProjectName: ht
 * @ClassName: MyUserDetailsService
 * @Author: hejialun
 * @Description: secuity获取用户接口
 * @Date: 2021/6/22 13:08
 */
@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private ISysUserRoleService iSysUserRoleService;
    @Autowired
    private RedisUtil redisUtil;
    //过期时间
    @Value("${jwt.expireTime}")
    public long EXPIRE_TIME = 0;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = iSysUserService.getUserInfoByUsername(username);
        if (sysUser == null) {      //用户不存在，认证失败
            throw new UsernameNotFoundException("用户名不存在");
        }
        ////用户已被禁用，认证失败
        if(!StrUtil.equals(sysUser.getState(),DicConstants.State.ENABLE)){
            throw new HtException("用户已被禁用！请联系管理员");
        }
        //定义权限集合对象
        List<GrantedAuthority> auths = new ArrayList<>();
        //定义权限数组
        List<String> roleCodes=new ArrayList<>();
        //定义菜单权限数组
        List<String> menuCodes=new ArrayList<>();
        //获取缓存中的数据
        Map<String, String> roleMap= (Map<String, String>) redisUtil.get(RedisConstants.USER_ROLE + username);
        if(ObjectUtil.isEmpty(roleMap)){
            //查询出
            //获取当前登录用户的角色
            List<SysRole> roles = iSysUserRoleService.findRoleByUserId(sysUser.getId());
            //获取用户按钮权限和菜单权限
            List<SysMenu> sysMenuList=sysMenuMapper.findByUserId(sysUser.getId());
            //设置角色权限集合
            roleCodes=roles.stream().map(SysRole::getCode).collect(Collectors.toList());
            //设置菜单权限集合
            menuCodes=sysMenuList.stream().map(SysMenu::getCode).collect(Collectors.toList());
            //缓存到redis里面
            roleMap=new HashMap<>();
            //设置角色权限
            roleMap.put(RedisConstants.SYS_ROLE_CODES, String.join(",", roleCodes));
            //设置菜单
            roleMap.put(RedisConstants.SYS_MENU_CODES,String.join(",", menuCodes));
            //将用户权限信息存到redis
            redisUtil.set(RedisConstants.USER_ROLE+sysUser.getUsername(),roleMap,EXPIRE_TIME);
        }else{
            //从缓存中获取权限
            roleCodes= Arrays.asList(roleMap.get(RedisConstants.SYS_ROLE_CODES).split(","));
            menuCodes= Arrays.asList(roleMap.get(RedisConstants.SYS_MENU_CODES).split(","));
        }

        //移除空值:解决无权限用户问题：A granted authority textual representation is required
        roleCodes= roleCodes.stream().filter(StrUtil::isNotEmpty).collect(Collectors.toList());
        menuCodes= menuCodes.stream().filter(StrUtil::isNotEmpty).collect(Collectors.toList());

        //设置角色权限
        auths.addAll(roleCodes.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
        //设置功能权限
        auths.addAll(menuCodes.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));


        return new User(sysUser.getUsername(), sysUser.getPassword(), auths);
    }
}